`include "defines.v"
`include "inst_defines.v"
`include "aluop_defines.v"
`include "csr_defines.v"

module id(
  input wire rst,
  input wire [31 : 0]instr_i,
  input wire [`REG_BUS]rs1_data_i,
  input wire [`REG_BUS]rs2_data_i,
  
  
  output reg rs1_r_ena_o,
  output reg [4 : 0]rs1_r_addr_o,
  output reg rs2_r_ena_o,
  output reg [4 : 0]rs2_r_addr_o,
  output reg rd_w_ena_o,
  output reg [4 : 0]rd_w_addr_o,

  output wire csr_r_ena_o,
  output wire csr_w_ena_o,
  output wire [11:0]csr_addr_o,
  

  output reg  [`REG_BUS]op1_o,
  output reg  [`REG_BUS]op2_o,
  output reg  [`REG_BUS]imm_o,
  output reg  [5:0]aluop_o,

  output wire skip_id_o
);

// 指令内容提取
wire[6:0] opcode = instr_i[6:0]   ;
wire[2:0] funct3 = instr_i[14:12] ;
wire[6:0] funct7 = instr_i[31:25] ;
wire[4:0] rd 	 = instr_i[11:7]  ;
wire[4:0] rs1 	 = instr_i[19:15] ;
wire[4:0] rs2  	 = instr_i[24:20] ;
wire[11:0] csr   = instr_i[31:20] ;

assign csr_addr_o = csr;
assign skip_id_o = ( opcode == `CSR_type ) && ( csr == `MCYCLE);

//译码出立即数
always @ (*) begin
    case (opcode)
        `R_type, `R_type_extend :
            imm_o = 0;
        `I_type, `I_type_extend, `I_type_load, `INST_JALR : 
            imm_o = {  {52{instr_i[31]}} , instr_i[31:20] };
        `S_type : 
            imm_o = {  {52{instr_i[31]}} , instr_i[31:25] , instr_i[11:7] };
        `B_type : 
            imm_o = {  {52{instr_i[31]}} , instr_i[7]     , instr_i[30:25] ,instr_i[11:8] ,1'b0 };
        `INST_LUI, `INST_AUIPC :
            imm_o = {  {33{instr_i[31]}} ,instr_i[30:12]    , 12'b0  };
        `INST_JAL : 
            imm_o = {  {44{instr_i[31]}} , instr_i[19:12] , instr_i[20]  ,  instr_i[30:21],1'b0 };
        `CSR_type :
            imm_o = {  {59{instr_i[19]}} , instr_i[19:15] };
        default: imm_o = 0;
    endcase
end  

//rd 写使能信号
    always @ (*) begin
        case(opcode)
            `R_type, `R_type_extend,`I_type, `I_type_extend, `I_type_load, `INST_JAL,`INST_JALR, `INST_LUI, `INST_AUIPC, `CSR_type  : 
                rd_w_ena_o = 1'b1;
            `S_type, `B_type  : 
                rd_w_ena_o = 1'b0;
            default : 
                rd_w_ena_o = 1'b0;
        endcase
    end
//csr 写使能信号
    assign csr_r_ena_o = ( opcode == `CSR_type );
    assign csr_w_ena_o = ( opcode == `CSR_type );

//rs1 ，rs2读使能信号

    always @ (*) begin
        case(opcode)
            `R_type,`R_type_extend, `S_type, `B_type : 
                {rs1_r_ena_o, rs2_r_ena_o} = 2'b11;
            `I_type, `I_type_extend, `I_type_load, `INST_JALR ,`INST_PUTCH: 
                {rs1_r_ena_o, rs2_r_ena_o} = 2'b10;
            `INST_JAL, `INST_LUI, `INST_AUIPC  : 
                {rs1_r_ena_o, rs2_r_ena_o} = 2'b00;
            `CSR_type:
                if(!funct3[2])
                    {rs1_r_ena_o, rs2_r_ena_o} = 2'b10;
                else
                    {rs1_r_ena_o, rs2_r_ena_o} = 2'b00;
            default : 
                {rs1_r_ena_o, rs2_r_ena_o} = 2'b00;
        endcase
    end
//第一个操作数
    always @ (*) begin
        if(rst == `RST)
            op1_o = `ZERO_WORD;
        else if(rs1_r_ena_o)
            op1_o = rs1_data_i;
        else if(!rs1_r_ena_o)
            op1_o = imm_o;
        else
            op1_o = `ZERO_WORD;
    end

//第二个操作数
    always @ (*) begin
        if(rst == `RST)
            op2_o = `ZERO_WORD;
        else if(rs2_r_ena_o)
            op2_o = rs2_data_i;
        else if(!rs2_r_ena_o)
            op2_o = imm_o;
        else
            op2_o = `ZERO_WORD;
    end

//alu_opcode

always @ (*) begin
        if(rst == `RST) begin
            rs1_r_addr_o = `REG_ADDR_0;
            rs2_r_addr_o = `REG_ADDR_0;
            rd_w_addr_o  = `REG_ADDR_0; 
            aluop_o      = `ALUOP_NOP;
            end
        else if( opcode == `INST_FALT )
            begin
                rs1_r_addr_o = 5'd10;
                aluop_o = `ALUOP_FALT;
            end
        else if( opcode == `INST_PUTCH )
            begin
                rs1_r_addr_o = 5'd10;
                aluop_o = `ALUOP_PUTCH;
            end
        else begin
            rs1_r_addr_o = rs1;
            rs2_r_addr_o = rs2;
            rd_w_addr_o  = rd;
            case (opcode)
                `R_type : begin  
                    case(funct3)
                        `INST_ADDSUB : begin
                            if(funct7 == 7'b0) aluop_o = `ALUOP_ADD;
                            else               aluop_o = `ALUOP_SUB;
                            end
                        
                        `INST_SLT  : aluop_o = `ALUOP_SLT;
                        `INST_SLTU : aluop_o = `ALUOP_SLTU;
                        `INST_AND  : aluop_o = `ALUOP_AND;
                        `INST_OR   : aluop_o = `ALUOP_OR;
                        `INST_XOR  : aluop_o = `ALUOP_XOR;
                        `INST_SLL  : aluop_o = `ALUOP_SLL;
                        `INST_SRLSRA : begin
                            if(funct7[6:1] == 6'b00) aluop_o = `ALUOP_SRL;
                            else                     aluop_o = `ALUOP_SRA;
                            end
                        default    : aluop_o = `ALUOP_NOP;    
                    endcase
                    end
                `R_type_extend : begin    
                    case(funct3)
                        `INST_ADDWSUBW : begin
                            if(funct7 == 7'b0) aluop_o = `ALUOP_ADDW;
                            else               aluop_o = `ALUOP_SUBW;
                         end   
                        `INST_SLLW : aluop_o = `ALUOP_SLLW;
                        `INST_SRLWSRAW : begin
                            if(funct7[6:1] == 6'b00)  aluop_o = `ALUOP_SRLW;
                            else                      aluop_o = `ALUOP_SRAW;
                        end
                        default    : aluop_o = `ALUOP_NOP;          
                    endcase
                    end
                `I_type : begin  
                    case(funct3)
                        `INST_ADDI  : aluop_o = `ALUOP_ADD;
                        `INST_SLTI  : aluop_o = `ALUOP_SLT;
                        `INST_SLTIU : aluop_o = `ALUOP_SLTU;
                        `INST_ANDI  : aluop_o = `ALUOP_AND;
                        `INST_ORI   : aluop_o = `ALUOP_OR;
                        `INST_XORI  : aluop_o = `ALUOP_XOR;
                        `INST_SLLI  : aluop_o = `ALUOP_SLL;
                        `INST_SRLISRAI : begin
                            if(funct7[6:1] == 6'b00) aluop_o = `ALUOP_SRL;
                            else                     aluop_o = `ALUOP_SRA;
                            end
                        default    : aluop_o = `ALUOP_NOP;    
                    endcase
                    end
                `I_type_extend : begin    
                    case(funct3)
                        `INST_ADDIW : aluop_o = `ALUOP_ADDW; 
                        `INST_SLLIW : aluop_o = `ALUOP_SLLW;
                        `INST_SRLIWSRAIW : begin
                            if(funct7[6:1] == 6'b00)  aluop_o = `ALUOP_SRLW;
                            else                      aluop_o = `ALUOP_SRAW;
                        end
                        default    : aluop_o = `ALUOP_NOP;          
                    endcase
                    end
                `I_type_load : begin
                    case(funct3)
                        `INST_LB : aluop_o = `ALUOP_LB;
                        `INST_LH : aluop_o = `ALUOP_LH;
                        `INST_LW : aluop_o = `ALUOP_LW;
                        `INST_LBU: aluop_o = `ALUOP_LBU;
                        `INST_LHU: aluop_o = `ALUOP_LHU;
                        `INST_LWU: aluop_o = `ALUOP_LWU;
                        `INST_LD : aluop_o = `ALUOP_LD;
                        default  : aluop_o = `ALUOP_NOP;  
                    endcase
                    end
                `S_type : begin
                    case (funct3)
                        `INST_SB : aluop_o = `ALUOP_SB;
                        `INST_SH : aluop_o = `ALUOP_SH;
                        `INST_SW : aluop_o = `ALUOP_SW;
                        `INST_SD : aluop_o = `ALUOP_SD;
                        default  : aluop_o = `ALUOP_NOP;  
                    endcase
                    end
                `B_type : begin
                    case (funct3)
                        `INST_BEQ : aluop_o = `ALUOP_BEQ;
                        `INST_BNE : aluop_o = `ALUOP_BNE;
                        `INST_BLT : aluop_o = `ALUOP_BLT;
                        `INST_BGE : aluop_o = `ALUOP_BGE;
                        `INST_BLTU: aluop_o = `ALUOP_BLTU;
                        `INST_BGEU: aluop_o = `ALUOP_BGEU;
                        default   : aluop_o = `ALUOP_NOP; 
                    endcase
                    end
                `CSR_type : begin
                    case (funct3)
                        `INST_CSRRW : aluop_o = `ALUOP_CSRRW;
                        `INST_CSRRS : aluop_o = `ALUOP_CSRRS;
                        `INST_CSRRC : aluop_o = `ALUOP_CSRRC;
                        `INST_CSRRWI: aluop_o = `ALUOP_CSRRW;
                        `INST_CSRRSI: aluop_o = `ALUOP_CSRRS;
                        `INST_CSRRCI: aluop_o = `ALUOP_CSRRC;
                        default   : aluop_o = `ALUOP_NOP; 
                    endcase
                    end
                `INST_JAL : begin
                    aluop_o = `ALUOP_JAL;
                    end
                `INST_JALR: begin
                    aluop_o = `ALUOP_JALR;
                    end
                `INST_LUI : begin
                    aluop_o = `ALUOP_LUI;
                    end
                `INST_AUIPC: begin
                    aluop_o = `ALUOP_AUIPC;
                    end
                
                `INST_NOP_OP: begin
                    aluop_o = `ALUOP_NOP;
                    end
                                  
                default   :
                    aluop_o = `ALUOP_NOP;
            endcase 
            end
    end

endmodule




